/*
 * Licensed to the Tai Ping Jin Ke
 *
 * Copyright (c) 2022 .
 * All rights reserved.
 * 项目名称：登录通-业务逻辑层
 * 版权说明：本软件属太平金融科技服务(上海)有限公司所有，在未获得太平金融科技服务(上海)有限公司正式授权情况下，任何企业和个人，不能获取、阅读、安装、传播本软件涉及的任何受知识产权保护的内容。
 */
package com.taiping.dlt.service;

import com.taiping.dlt.application.constant.dao.DataSourceEnum;
import com.taiping.dlt.base.BaseService;
import com.taiping.dlt.client.service.AuthorizeServiceClient;
import com.taiping.dlt.converter.AuthLoginDOConverter;
import com.taiping.dlt.converter.AuthLoginQOConverter;
import com.taiping.dlt.dataobject.AuthLoginDO;
import com.taiping.dlt.pojo.bo.AuthLoginBO;
import com.taiping.dlt.pojo.query.AuthLoginQO;
import com.taiping.dlt.repository.IRepository;
import com.taiping.dlt.strategy.RepositoryHandlerContext;
import com.taiping.dlt.strategy.RepositoryHandlerFactory;
import com.taipingframework.utility.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.util.List;

@Slf4j
@Service
public class AccountService extends BaseService {

    /**
     * 禁用账户/(逻辑)删除账户
     */
    public Mono<Boolean> disableAccount(AuthLoginBO authLoginBO) {
        if (DataSourceEnum.NONE != dltProperty.getDataSource()) {
            IRepository<AuthLoginDO> repository = RepositoryHandlerFactory.createRepository(new ParameterizedTypeReference<IRepository<AuthLoginDO>>() {
            });
            RepositoryHandlerContext<AuthLoginDO> repositoryHandlerContext = new RepositoryHandlerContext<>(repository);

            AuthLoginDO authLoginDO = AuthLoginDOConverter.convert(authLoginBO);
            return repositoryHandlerContext.queryForList(authLoginDO)
                    .flatMap(loginDO -> Mono.just(loginDO.getLoginId()))
                    .collectList()
                    .flatMap(repositoryHandlerContext::batchDelete)
                    .doOnError(e -> log.error("禁用账户/(逻辑)删除账户失败，参数login-name是：{}", authLoginBO.getLoginName()))
                    .onErrorResume(e -> Mono.error(new ServiceException(e)));
        } else {
            AuthLoginQO loginQO = AuthLoginQOConverter.convert(authLoginBO);
            return AuthorizeServiceClient.disableClientHandler(loginQO)
                    .onErrorResume(e -> Mono.error(new ServiceException(e)));
        }
    }

    /**
     * 接收推送到当前业务系统的数据
     */
    public Mono<Boolean> receive(List<AuthLoginBO> authLoginBOList) {
        if (DataSourceEnum.NONE != dltProperty.getDataSource()) {
            IRepository<AuthLoginDO> repository = RepositoryHandlerFactory.createRepository(new ParameterizedTypeReference<IRepository<AuthLoginDO>>() {
            });
            RepositoryHandlerContext<AuthLoginDO> repositoryHandlerContext = new RepositoryHandlerContext<>(repository);
            return repositoryHandlerContext.batchInsert(AuthLoginDOConverter.convert(authLoginBOList))
                    .count()
                    .map(count -> count.intValue() == authLoginBOList.size())
                    .onErrorResume(e -> Mono.error(new ServiceException(e)));
        } else {
            // 调用后端微服务接口，去mysql或oracle中插入用户信息。此处，需要特别说明：mysql或oracle支持reactive模式的r2dbc驱动，目前并不支持java8。
            // 至少需要JDK11以上的r2dbc驱动才能对mysql或oracle有较好的支持。因此，在这里我们直接远程异步调用后端微服务即可。
            // 当然，这样的做法会增加调用链路，在性能层面存在一定影响。所以，比较好的做法是将用户登录所需的数据
            // 从关系型数据库同步到elasticsearch、mongodb、redis中，直接在上方做校验即可。
            return AuthorizeServiceClient.pushClientHandler(authLoginBOList)
                    .onErrorResume(e -> Mono.error(new ServiceException(e)));
        }
    }

}
